/**
 * \file    common.h
 * \brief   Parser generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    September 17, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#ifndef COMMON_H
#define COMMON_H

#ifdef NDEBUG
#   define DEBUG_MESSAGE(...)
#else
#   warning DEBUG enabled
#   include <stdio.h>
#   define DEBUG_MESSAGE(...) do {printf  (__VA_ARGS__);printf("\n");} while(0)
#endif

#if defined(LPP_STRINGIFY_) || defined(LPP_STRINGIFY)
#   error Change that name
#endif
#define LPP_STRINGIFY_(s) #s
#define LPP_STRINGIFY(s) LPP_STRINGIFY_(s)

#include <iostream>
#include <cstddef>
#include <string>
#include <vector>
#include <deque>
#include <unordered_set>
#include <set>
#include <regex>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
#include <functional>
#include <boost/variant.hpp>
#include <boost/format.hpp>

#if 1
#define LPP_NAMESPACE_NAME
#define LPP_NAMESPACE_BEGIN
#define LPP_NAMESPACE_END
#define LPP_NAMESPACE_USING
#else
#define LPP_NAMESPACE_NAME _LPP
#define LPP_NAMESPACE_BEGIN namespace LPP_NAMESPACE_NAME {
#define LPP_NAMESPACE_END }
#define LPP_NAMESPACE_USING using namespace LPP_NAMESPACE_NAME;
#endif

LPP_NAMESPACE_BEGIN
/* a few forward declarations... */
typedef size_t Index;

typedef std::string String;
typedef std::deque<String> StringList;
typedef std::set<String> StringSet;
typedef std::set<StringList> StringLists;

std::ostream& operator<< (std::ostream &out, StringList const & list);

typedef std::regex Regex;

class Symbol;
typedef std::shared_ptr<Symbol> SymbolRef;
typedef std::weak_ptr<Symbol> SymbolWRef;
typedef std::deque<SymbolRef> SymbolRefList;
typedef std::set<SymbolRef> SymbolRefSet;
typedef SymbolRefList::size_type SymbolIndex;

int compare(Symbol const & a, Symbol const & b);
int compare(SymbolRef const & a, SymbolRef const & b);
int compare(SymbolWRef const & a, SymbolWRef const & b);
int compare(SymbolRefList const & a, SymbolRefList const & b);
bool operator==(SymbolWRef const & __lhs, SymbolWRef const & __rhs);
bool operator==(Symbol const & a, Symbol const & b);
bool operator==(SymbolRef const & a, SymbolRef const & b);
bool operator==(SymbolWRef const & a, SymbolWRef const & b);
bool operator< (SymbolWRef const & a, SymbolWRef const & b);
bool operator< (SymbolRef const & a, SymbolRef const & b);
bool operator< (Symbol const & a, Symbol const & b);

class Rule;
typedef std::shared_ptr<Rule> RuleRef;
typedef std::weak_ptr<Rule> RuleWRef;
typedef std::deque<RuleRef> RuleRefList; // the RuleRefList owns the rules
typedef std::deque<RuleWRef> RuleWRefList;
typedef RuleRefList::size_type RuleIndex;

int compare(Rule const & __lhs, Rule const & __rhs);/*! Comparison only holds on the symbols. */
int compare(RuleRef const & __lhs, RuleRef const & __rhs);
int compare(RuleWRef const & __lhs, RuleWRef const & __rhs);
bool operator<(RuleWRef const & __a, RuleWRef const & __b);
bool operator<(RuleRef const & __a, RuleRef const & __b);

class State;
typedef std::shared_ptr<State> StateRef;
typedef std::weak_ptr<State> StateWRef;
typedef std::deque<State> StateList;
typedef std::deque<StateRef> StateRefList;
typedef std::reference_wrapper<State> StateWrap;

int compare(State const & __a, State const & __b);
int compare(StateWrap const & __a, StateWrap const & __b);
int compare(StateRef const & __a, StateRef const & __b);
bool operator<(const State & a, const State & b);
bool operator==(const StateWrap & a, const StateWrap & b);
bool operator==(const StateRef & a, const StateRef & b);

class Action;
typedef std::shared_ptr<Action> ActionRef;
typedef std::weak_ptr<Action> ActionWRef;
typedef std::deque<ActionRef> ActionRefList;
typedef long int ActionOffset; // must be signed !
typedef ActionRefList::size_type ActionIndex;
typedef std::map<SymbolRef,ActionRef> ActionRefMap;
typedef Index ActionCode;

class Item;
typedef std::shared_ptr<Item> ItemRef;
typedef std::weak_ptr<Item> ItemWRef;
typedef std::deque<Item> ItemList;
typedef std::deque<ItemRef> ItemRefList;
typedef ItemRefList::size_type ItemIndex;
typedef std::set<ItemRef> ItemRefSet;

int compare(Item const & __lhs, Item const & __rhs);
int compare(ItemRef const & __lhs, ItemRef const & __rhs);
int compare(ItemWRef const & __lhs, ItemWRef const & __rhs);
bool operator<(Item const & __lhs,Item const & __rhs);
bool operator==(Item const & __lhs,Item const & __rhs);
bool operator<(ItemRef const & __lhs,ItemRef const & __rhs);
bool operator==(ItemRef const & __lhs,ItemRef const & __rhs);
bool operator==(ItemWRef const & __lhs, ItemWRef const & __rhs);
bool operator<(ItemWRef const & __lhs,ItemWRef const & __rhs);

class Grammar;
typedef std::shared_ptr<Grammar> GrammarRef;

class Parser;
class Generator;
class Builder;
class Coder;

typedef boost::format Format;

template <typename T>
int compare_Ref(T const & __lhs, T const & __rhs) {
    if (&__lhs==&__rhs) return 0;
    if (__lhs) {
        if (__rhs) {
            return compare(*__lhs,*__rhs);
        }
        return 1;
    }
    if (__rhs) {
        return -1;
    }
    return 0;
}

template <typename T>
int compare_WRef(T const & __lhs, T const & __rhs) {
    typedef std::shared_ptr<typename T::element_type> Ref;
    Ref const lhs = __lhs.lock();
    Ref const rhs = __rhs.lock();
    return compare_Ref<Ref>(lhs,rhs);
}

template <typename T>
int compare_Wrap(T const & __lhs, T const & __rhs) {
    typename T::type const a = __lhs;
    typename T::type const b = __rhs;
    return compare(a,b);
}

std::regex operator ""_regex (const char * s, size_t num_chars);

template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

LPP_NAMESPACE_END

namespace std {
template <> struct hash<LPP_NAMESPACE_NAME::SymbolRef>
{
    size_t operator()(const LPP_NAMESPACE_NAME::SymbolRef & __s) const {
        return __s? reinterpret_cast<std::uintptr_t>(__s.get()): 0;
    }
};
template <> struct hash<LPP_NAMESPACE_NAME::SymbolWRef>
{
    size_t operator()(const LPP_NAMESPACE_NAME::SymbolWRef & __s) const {
        return hash<LPP_NAMESPACE_NAME::SymbolRef>()(__s.lock());
        // return s? hash<std::string>(s->name_m): 0; define Symbol first
    }
};
template <> struct hash<LPP_NAMESPACE_NAME::RuleRef> {
    size_t operator()(LPP_NAMESPACE_NAME::RuleRef const & x) const;
};
template <> struct hash<LPP_NAMESPACE_NAME::ItemRef> {
    size_t operator()(LPP_NAMESPACE_NAME::ItemRef const & x) const;
};
template <> struct hash<LPP_NAMESPACE_NAME::ItemWRef>
{
    size_t operator()(LPP_NAMESPACE_NAME::ItemWRef const & __s) const;
};
template <> struct less<LPP_NAMESPACE_NAME::ItemWRef> {
    bool operator()(LPP_NAMESPACE_NAME::ItemWRef const & __lhs,LPP_NAMESPACE_NAME::ItemWRef const & __rhs) const;
};
}

#endif // COMMON_H
